// e_lab1.cpp
// RDB 22 Sep 2010

#include "config.h"
#if BUILD_LAB1 // build this

/////////////////////////////////////////////////////////////////////////////////
// Header

#include "qec.h" // C++ base include for QE
#include "demoncore.h"

// returns true if a value is in a range
#define IN_RANGE(_t_, _min_, _max_) ((_min_ < t) && (_t_ < _max_))
#define ABS(_x_) ((_x_) < 0 ? -(_x_) : (_x_))

// There are two states: diastolic (rest) and systolic (active).
// They are indexed 0 and 1 in the two arrays.
// RDB 26 Aug 2010
const int8 aHeartSize [] = { 1, 3 };
const flt32 aHeartDelay [] = { 0.7, 0.3 };

// This is the grid that is shown as well as the limits for the
// bouncing sphere.
// RDB 22 Sep 2010
#define REGION_SIZE 10

// current state of the heart: starts at rest
// RDB 26 Aug 2010
bit heartState = 1;

// Records the last time the heart state changed.
// RDB 22 Sep 2010
flt32 lastChangeTime = 0;

// Controls whether the bouncing sphere is included or not.
// RDB 22 Sep 2010
#define SPHERE 1

#if SPHERE
// Records the last frame time
// RDB 22 Sep 2010
flt32 lastUpdateTime = 0;

// Size of the sphere (small)
// RDB 22 Sep 2010
#define SPHERE_SIZE 0.1

// Position of the sphere
// RDB 22 Sep 2010
Vec3 spherePos(-2,0,1);

// Velocity of the sphere. Only back and forth on the x-axis
// RDB 22 Sept 2010
Vec3 sphereVel(2.5,0,0);
#endif // SPHERE

/////////////////////////////////////////////////////////////////////////////////
// Implementation

#if SPHERE
// Draws the sphere using GLUT method.
// RDB 22 Sept 2010
int drawSphere()
{
   // Go to position
   glTranslatef(spherePos.x, spherePos.y, spherePos.z);
   glColor3f(1,1,1); // color is white
   glutWireSphere(SPHERE_SIZE, 5, 5); // 5, 5 is good for a small sphere like this one

   return 0;
} // drawSphere()
#endif // SPHERE

// The idea here is that a triangle that changes in size periodically kind of
// looks like a beating heart. Would be better with sound!
// RDB 11 Aug 10
int drawHeart()
{
   flt32 sz;

   // color = red
   glColor3f(1, 0, 0);

   // Set the size according to the current state 
   sz = aHeartSize[heartState];

   // draw a single triangle around the origin.
   glBegin(GL_TRIANGLES);
      glVertex3f(-sz, -sz, 0);
      glVertex3f(sz, -sz, 0);
      glVertex3f(0, sz, 0);
   glEnd();

   return 0;
} // drawHeart()

#if SPHERE
int updateSphere()
{
   flt32 t, tDelta;

   // update the timer and compute the elapsed time, tDelta
   t = qeTimeFrame();
   tDelta = t - lastUpdateTime;

   // compute new position
   spherePos += sphereVel * tDelta;
   lastUpdateTime = t;

   // check for bounds and bounce
   if (spherePos.x < -REGION_SIZE/2)
   {
      sphereVel.x = ABS(spherePos.x);
   } 
   else if (spherePos.x > REGION_SIZE/2)
   {
      sphereVel.x = -ABS(spherePos.x);
   } // if

   return 0;
} // updateSphere()
#endif // SPHERE

// Change the heart state based on the current time and the delay
// associated with the current state
// RDB 11 Aug 10
int updateHeart()
{
   flt32 currentTime;
   
   // If the time since the last state change + delay > current time
   // then it is time to change state.
   currentTime = qeTimeFrame();
   if (lastChangeTime + aHeartDelay[heartState] < currentTime)
   {
      heartState = !heartState;
	  lastChangeTime = currentTime;
   }

   return 0;
} // updateHeart()

// Main loop does object updates and draws.
// RDB 22 Sep 2010
int gameMainLoop()
{
   // updating
   updateHeart();
#if SPHERE
   updateSphere();
#endif // SPHERE
   
   // drawing
   qefnDrawGrid(10,1);
   drawHeart();
#if SPHERE
   drawSphere();
#endif // SPHERE
   
   return 0;
} // gameMainLoop()

/////////////////////////////////////////////////////////////////////////////////
// Main

// Entry point for the engine
// RDB 11 Aug 10
int qeMain(int argc,chr *argv[])
{
   qePrintf("Lab 1 application\n");

   // Set the main loop callback
   if (!qeObjAddFnc(gameMainLoop))
      qePrintf("** qeObjAddFnc failed\n");

   // turn control over to the engine
   qeForever();
   
   return 0;
} // qeMain()

#endif // build this
// EOF
